﻿using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace QuickTest.Core.Compilation
{
    /// <summary>
    /// Class responsible for compiling a project.
    /// </summary>
    public class CompileProject : ICompilable<Project>
    {
        public void Compile(Project project, ICompiler compiler, DirectoryUri outputDirectory)
        {
            try
            {
                compiler.Compile(CreateFileToCompile(project, outputDirectory));
            }
            finally
            {
                DeleteWorkingFile(project);
            }
        }

        private FileUri GetWorkingFileUri(Project project)
        {
            return new FileUri(project.FileUri.AbsolutePath + "_copy");
        }

        private void DeleteWorkingFile(Project project)
        {
            string targetFile = GetWorkingFileUri(project).AbsolutePath;
            if (File.Exists(targetFile))
            {
                File.Delete(targetFile);
            }
        }

        private FileUri CreateFileToCompile(Project project, DirectoryUri outputDirectory)
        {
            CreateOutputDirectory(outputDirectory);

            FileUri workingFile = GetWorkingFileUri(project);

            CreateWorkingFile(project.FileUri, workingFile);

            XElement projectXml = GetProjectXml(workingFile);

            ChangeOutputPath(outputDirectory, projectXml);

            SaveWorkingFile(workingFile, projectXml);

            return workingFile;
        }

        private void CreateOutputDirectory(DirectoryUri outputDirectory)
        {
            Directory.CreateDirectory(outputDirectory.AbsolutePath);
        }

        private void CreateWorkingFile(FileUri projectFile, FileUri targetFile)
        {
            File.Copy(projectFile.AbsolutePath, targetFile.AbsolutePath, true);
        }

        private void SaveWorkingFile(FileUri targetFile, XElement projectXml)
        {
            File.WriteAllText(targetFile.AbsolutePath, projectXml.ToString());
        }

        private void ChangeOutputPath(DirectoryUri outputDirectory, XContainer projectXml)
        {
            foreach (XElement outputPath in projectXml.Descendants(XName.Get("OutputPath", Project.ProjectFileXmlNamespace))
                .Select(element => element))
            {
                outputPath.Value = outputDirectory.AbsolutePath;
            }
        }

        private XElement GetProjectXml(FileUri targetFile)
        {
            return XElement.Parse(File.ReadAllText(targetFile.AbsolutePath));
        }
    }
}